From 3afe806f6fc892fe7ba31e2d7f2059d0ac1766da Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 17 Oct 2005 15:15:17 +0100 Subject: [PATCH] Make the event-channel pending and mask arrays consist of longs. Thi sensures appropriate alignment for architectures that require it, and also allows us to naturally support up to 4096 event channels per 64-bit guest. Moved 'n_vcpu' field from shared_info to start_info. Really it ought to disappear altogether as the info can be derived from xenstore. Fix a weird bug in XendDomainInfo where 'vcpus' information for a domain defaults to floating point value 1.0 rather than integer 1. This looks like a Python bug to me, but in any case it is 'fixed' by explicitly converting the default value to an integer. Signed-off-by: Keir Fraser --- .../arch/ia64/xen/drivers/evtchn_ia64.c | 8 ++--- .../arch/xen/i386/kernel/smpboot.c | 8 ++--- linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c | 12 +++---- .../arch/xen/x86_64/kernel/smpboot.c | 4 +-- .../asm-xen/asm-i386/mach-xen/smpboot_hooks.h | 2 +- .../asm-x86_64/mach-xen/smpboot_hooks.h | 2 +- linux-2.6-xen-sparse/include/asm-xen/evtchn.h | 5 +-- tools/libxc/xc_linux_build.c | 4 +-- tools/libxc/xc_vmx_build.c | 3 -- tools/python/xen/xend/XendDomainInfo.py | 2 +- xen/arch/ia64/vmx/vmx_support.c | 8 ++--- xen/arch/x86/domain_build.c | 8 ++--- xen/arch/x86/vmx_io.c | 12 +++---- xen/common/keyhandler.c | 2 +- xen/include/public/xen.h | 36 ++++++++++--------- xen/include/xen/event.h | 9 ++--- xen/include/xen/sched.h | 2 +- 17 files changed, 62 insertions(+), 65 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c index bd576ce869..0027b82a62 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/evtchn_ia64.c @@ -94,7 +94,7 @@ void notify_remote_via_irq(int irq) irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - u32 l1, l2; + unsigned long l1, l2; unsigned int l1i, l2i, port; irqreturn_t (*handler)(int, void *, struct pt_regs *); shared_info_t *s = HYPERVISOR_shared_info; @@ -108,14 +108,14 @@ irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) while ( l1 != 0 ) { l1i = __ffs(l1); - l1 &= ~(1 << l1i); + l1 &= ~(1UL << l1i); while ( (l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i]) != 0 ) { l2i = __ffs(l2); - l2 &= ~(1 << l2i); + l2 &= ~(1UL << l2i); - port = (l1i << 5) + l2i; + port = (l1i * BITS_PER_LONG) + l2i; if ( (handler = evtchns[port].handler) != NULL ) { clear_evtchn(port); diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index b13abf720e..01e245e3ab 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1123,7 +1123,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) * If SMP should be disabled, then really disable it! */ if (!max_cpus) { - HYPERVISOR_shared_info->n_vcpu = 1; + xen_start_info->n_vcpu = 1; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); smpboot_clear_io_apic_irqs(); #if 0 @@ -1153,12 +1153,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) */ Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map)); #endif - Dprintk("CPU present map: %lx\n", - (1UL << HYPERVISOR_shared_info->n_vcpu) - 1); + Dprintk("CPU present map: %lx\n", (1UL << xen_start_info->n_vcpu) - 1); kicked = 1; - for (cpu = 1; kicked < NR_CPUS && - cpu < HYPERVISOR_shared_info->n_vcpu; cpu++) { + for (cpu = 1; kicked < NR_CPUS && cpu < xen_start_info->n_vcpu; cpu++) { if (max_cpus <= cpucount+1) continue; diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c index 80e017684b..1d27f11910 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c @@ -71,8 +71,8 @@ static unsigned long pirq_needs_unmask_notify[NR_PIRQS/sizeof(unsigned long)]; #ifdef CONFIG_SMP -static u8 cpu_evtchn[NR_EVENT_CHANNELS]; -static u32 cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/32]; +static u8 cpu_evtchn[NR_EVENT_CHANNELS]; +static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG]; #define active_evtchns(cpu,sh,idx) \ ((sh)->evtchn_pending[idx] & \ @@ -137,7 +137,7 @@ EXPORT_SYMBOL(force_evtchn_callback); /* NB. Interrupts are disabled on entry. */ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) { - u32 l1, l2; + unsigned long l1, l2; unsigned int l1i, l2i, port; int irq, cpu = smp_processor_id(); shared_info_t *s = HYPERVISOR_shared_info; @@ -149,13 +149,13 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); while (l1 != 0) { l1i = __ffs(l1); - l1 &= ~(1 << l1i); + l1 &= ~(1UL << l1i); while ((l2 = active_evtchns(cpu, s, l1i)) != 0) { l2i = __ffs(l2); - l2 &= ~(1 << l2i); + l2 &= ~(1UL << l2i); - port = (l1i << 5) + l2i; + port = (l1i * BITS_PER_LONG) + l2i; if ((irq = evtchn_to_irq[port]) != -1) do_IRQ(irq, regs); else diff --git a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c index 48abf11507..b48b559a45 100644 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c @@ -1045,7 +1045,7 @@ static int __cpuinit smp_sanity_check(unsigned max_cpus) */ if (!max_cpus) { #ifdef CONFIG_XEN - HYPERVISOR_shared_info->n_vcpu = 1; + xen_start_info->n_vcpu = 1; #endif printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); #ifndef CONFIG_XEN @@ -1082,7 +1082,7 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus) int apicid = cpu_present_to_apicid(i); if (physid_isset(apicid, phys_cpu_present_map)) { #else - if (i < HYPERVISOR_shared_info->n_vcpu) { + if (i < xen_start_info->n_vcpu) { #endif cpu_set(i, cpu_present_map); /* possible map would be different if we supported real diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h index 28adeaf244..fa85aa2cfe 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h @@ -52,4 +52,4 @@ static inline void smpboot_setup_io_apic(void) } -#define smp_found_config (HYPERVISOR_shared_info->n_vcpu > 1) +#define smp_found_config (xen_start_info->n_vcpu > 1) diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h index 28adeaf244..fa85aa2cfe 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h @@ -52,4 +52,4 @@ static inline void smpboot_setup_io_apic(void) } -#define smp_found_config (HYPERVISOR_shared_info->n_vcpu > 1) +#define smp_found_config (xen_start_info->n_vcpu > 1) diff --git a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h index f2523926d8..127cf8e72f 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h +++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h @@ -99,8 +99,9 @@ static inline void unmask_evtchn(int port) * like a real IO-APIC we 'lose the interrupt edge' if the channel is * masked. */ - if (synch_test_bit (port, &s->evtchn_pending[0]) && - !synch_test_and_set_bit(port>>5, &vcpu_info->evtchn_pending_sel)) { + if (synch_test_bit(port, &s->evtchn_pending[0]) && + !synch_test_and_set_bit(port / BITS_PER_LONG, + &vcpu_info->evtchn_pending_sel)) { vcpu_info->evtchn_upcall_pending = 1; if (!vcpu_info->evtchn_upcall_mask) force_evtchn_callback(); diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 5cdb568bc0..1185fc020e 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -636,6 +636,7 @@ static int setup_guest(int xc_handle, start_info->store_evtchn = store_evtchn; start_info->console_mfn = *console_mfn; start_info->console_evtchn = console_evtchn; + start_info->n_vcpu = vcpus; if ( initrd_len != 0 ) { start_info->mod_start = vinitrd_start; @@ -653,9 +654,6 @@ static int setup_guest(int xc_handle, for ( i = 0; i < MAX_VIRT_CPUS; i++ ) shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - shared_info->n_vcpu = vcpus; - printf(" VCPUS: %d\n", shared_info->n_vcpu); - munmap(shared_info, PAGE_SIZE); /* Send the page update requests down to the hypervisor. */ diff --git a/tools/libxc/xc_vmx_build.c b/tools/libxc/xc_vmx_build.c index 5dd55e94f7..2f8a5ec72d 100644 --- a/tools/libxc/xc_vmx_build.c +++ b/tools/libxc/xc_vmx_build.c @@ -519,9 +519,6 @@ static int setup_guest(int xc_handle, for ( i = 0; i < MAX_VIRT_CPUS; i++ ) shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - shared_info->n_vcpu = vcpus; - printf(" VCPUS: %d\n", shared_info->n_vcpu); - munmap(shared_info, PAGE_SIZE); /* Populate the event channel port in the shared page */ diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 79fdd38a9a..3615aed8d9 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -439,7 +439,7 @@ class XendDomainInfo: defaultInfo('on_crash', lambda: "restart") defaultInfo('cpu', lambda: None) defaultInfo('cpu_weight', lambda: 1.0) - defaultInfo('vcpus', lambda: 1) + defaultInfo('vcpus', lambda: int(1)) defaultInfo('vcpu_avail', lambda: (1 << self.info['vcpus']) - 1) defaultInfo('bootloader', lambda: None) defaultInfo('backend', lambda: []) diff --git a/xen/arch/ia64/vmx/vmx_support.c b/xen/arch/ia64/vmx/vmx_support.c index afd0f650d0..4da31f2332 100644 --- a/xen/arch/ia64/vmx/vmx_support.c +++ b/xen/arch/ia64/vmx/vmx_support.c @@ -49,7 +49,7 @@ void vmx_wait_io(void) */ if (test_and_clear_bit(port, &d->shared_info->evtchn_pending[0])) { - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); vmx_io_assist(v); } @@ -67,7 +67,7 @@ void vmx_wait_io(void) * nothing losed. Next loop will check I/O channel to fix this * window. */ - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); } else break; @@ -139,8 +139,8 @@ void vmx_intr_assist(struct vcpu *v) /* Clear indicator specific to interrupt delivered from DM */ if (test_and_clear_bit(port, &d->shared_info->evtchn_pending[0])) { - if (!d->shared_info->evtchn_pending[port >> 5]) - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + if (!d->shared_info->evtchn_pending[port/BITS_PER_LONG]) + clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); if (!v->vcpu_info->evtchn_pending_sel) clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 69b0ddd58b..38a3cb2c99 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -557,10 +557,9 @@ int construct_dom0(struct domain *d, /* Mask all upcalls... */ for ( i = 0; i < MAX_VIRT_CPUS; i++ ) d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1; - d->shared_info->n_vcpu = num_online_cpus(); - for ( i = 1; i < d->shared_info->n_vcpu; i++ ) - (void)alloc_vcpu(d, i, i % num_online_cpus()); + for ( i = 1; i < num_online_cpus(); i++ ) + (void)alloc_vcpu(d, i, i); /* Set up monitor table */ update_pagetables(v); @@ -588,7 +587,8 @@ int construct_dom0(struct domain *d, /* Set up start info area. */ si = (start_info_t *)vstartinfo_start; memset(si, 0, PAGE_SIZE); - si->nr_pages = nr_pages; + si->nr_pages = nr_pages; + si->n_vcpu = num_online_cpus(); if ( opt_dom0_translate ) { diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c index 1d904e43a9..e6536b31a1 100644 --- a/xen/arch/x86/vmx_io.c +++ b/xen/arch/x86/vmx_io.c @@ -684,15 +684,15 @@ int vmx_clear_pending_io_event(struct vcpu *v) struct domain *d = v->domain; int port = iopacket_port(d); - /* evtchn_pending is shared by other event channels in 0-31 range */ - if (!d->shared_info->evtchn_pending[port>>5]) - clear_bit(port>>5, &v->vcpu_info->evtchn_pending_sel); + /* evtchn_pending_sel bit is shared by other event channels. */ + if (!d->shared_info->evtchn_pending[port/BITS_PER_LONG]) + clear_bit(port/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel); - /* Note: VMX domains may need upcalls as well */ + /* Note: VMX domains may need upcalls as well. */ if (!v->vcpu_info->evtchn_pending_sel) clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); - /* clear the pending bit for port */ + /* Clear the pending bit for port. */ return test_and_clear_bit(port, &d->shared_info->evtchn_pending[0]); } @@ -726,7 +726,7 @@ void vmx_wait_io() break; /* Events other than IOPACKET_PORT might have woken us up. In that case, safely go back to sleep. */ - clear_bit(port>>5, ¤t->vcpu_info->evtchn_pending_sel); + clear_bit(port/BITS_PER_LONG, ¤t->vcpu_info->evtchn_pending_sel); clear_bit(0, ¤t->vcpu_info->evtchn_upcall_pending); } while(1); } diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index 0f1bbb9872..acbfd094bc 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -136,7 +136,7 @@ static void do_task_queues(unsigned char key) &d->shared_info->evtchn_pending[0]), test_bit(v->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_mask[0]), - test_bit(v->virq_to_evtchn[VIRQ_DEBUG]>>5, + test_bit(v->virq_to_evtchn[VIRQ_DEBUG]/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel)); send_guest_virq(v, VIRQ_DEBUG); } diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index c0111b5027..3c2d0094f2 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -260,8 +260,11 @@ typedef struct unsigned long args[6]; } multicall_entry_t; -/* Event channel endpoints per domain. */ -#define NR_EVENT_CHANNELS 1024 +/* + * Event channel endpoints per domain: + * 1024 if a long is 32 bits; 4096 if a long is 64 bits. + */ +#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64) /* * Per-VCPU information goes here. This will be cleaned up more when Xen @@ -295,7 +298,7 @@ typedef struct vcpu_info { */ uint8_t evtchn_upcall_pending; uint8_t evtchn_upcall_mask; - uint32_t evtchn_pending_sel; + unsigned long evtchn_pending_sel; #ifdef __ARCH_HAS_VCPU_INFO arch_vcpu_info_t arch; #endif @@ -333,16 +336,14 @@ typedef struct shared_info { vcpu_time_info_t vcpu_time[MAX_VIRT_CPUS]; - uint32_t n_vcpu; - /* - * A domain can have up to 1024 "event channels" on which it can send - * and receive asynchronous event notifications. There are three classes - * of event that are delivered by this mechanism: + * A domain can create "event channels" on which it can send and receive + * asynchronous event notifications. There are three classes of event that + * are delivered by this mechanism: * 1. Bi-directional inter- and intra-domain connections. Domains must - * arrange out-of-band to set up a connection (usually the setup - * is initiated and organised by a privileged third party such as - * software running in domain 0). + * arrange out-of-band to set up a connection (usually by allocating + * an unbound 'listener' port and avertising that via a storage service + * such as xenstore). * 2. Physical interrupts. A domain with suitable hardware-access * privileges can bind an event-channel port to a physical interrupt * source. @@ -350,8 +351,8 @@ typedef struct shared_info { * port to a virtual interrupt source, such as the virtual-timer * device or the emergency console. * - * Event channels are addressed by a "port index" between 0 and 1023. - * Each channel is associated with two bits of information: + * Event channels are addressed by a "port index". Each channel is + * associated with two bits of information: * 1. PENDING -- notifies the domain that there is a pending notification * to be processed. This bit is cleared by the guest. * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING @@ -363,11 +364,11 @@ typedef struct shared_info { * * To expedite scanning of pending notifications, any 0->1 pending * transition on an unmasked channel causes a corresponding bit in a - * 32-bit selector to be set. Each bit in the selector covers a 32-bit - * word in the PENDING bitfield array. + * per-vcpu selector word to be set. Each bit in the selector covers a + * 'C long' in the PENDING bitfield array. */ - uint32_t evtchn_pending[32]; - uint32_t evtchn_mask[32]; + unsigned long evtchn_pending[sizeof(unsigned long) * 8]; + unsigned long evtchn_mask[sizeof(unsigned long) * 8]; /* * Wallclock time: updated only by control software. Guests should base @@ -422,6 +423,7 @@ typedef struct start_info { unsigned long mfn_list; /* VIRTUAL address of page-frame list. */ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ + uint32_t n_vcpu; int8_t cmd_line[MAX_GUEST_CMDLINE]; } start_info_t; diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 8f527b0c83..e8a8bc2b5b 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -28,10 +28,11 @@ static inline void evtchn_set_pending(struct vcpu *v, int port) shared_info_t *s = d->shared_info; /* These four operations must happen in strict order. */ - if ( !test_and_set_bit(port, &s->evtchn_pending[0]) && - !test_bit (port, &s->evtchn_mask[0]) && - !test_and_set_bit(port>>5, &v->vcpu_info->evtchn_pending_sel) && - !test_and_set_bit(0, &v->vcpu_info->evtchn_upcall_pending) ) + if ( !test_and_set_bit(port, &s->evtchn_pending[0]) && + !test_bit (port, &s->evtchn_mask[0]) && + !test_and_set_bit(port / BITS_PER_LONG, + &v->vcpu_info->evtchn_pending_sel) && + !test_and_set_bit(0, &v->vcpu_info->evtchn_upcall_pending) ) { evtchn_notify(v); } diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4250205268..0f012456af 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -19,7 +19,7 @@ extern rwlock_t domlist_lock; /* A global pointer to the initial domain (DOM0). */ extern struct domain *dom0; -#define MAX_EVTCHNS 1024 +#define MAX_EVTCHNS NR_EVENT_CHANNELS #define EVTCHNS_PER_BUCKET 128 #define NR_EVTCHN_BUCKETS (MAX_EVTCHNS / EVTCHNS_PER_BUCKET) -- 2.30.2